/**
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License
 * at http://www.mozilla.org/MPL/
 * <p>
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and
 * limitations under the License.
 * <p>
 * The Original Code is RabbitMQ HTTP authentication.
 * <p>
 * The Initial Developer of the Original Code is VMware, Inc.
 * Copyright (c) 2017 Pivotal Software, Inc.  All rights reserved.
 */

package com.rabbitmq.examples;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

import static java.util.Arrays.asList;
import static org.springframework.util.StringUtils.collectionToDelimitedString;

/**
 *
 */
@RestController
@RequestMapping(path = "/auth", method = {RequestMethod.GET, RequestMethod.POST})
public class AuthBackendHttpController {

    private static final Logger LOGGER = LoggerFactory.getLogger(AuthBackendHttpController.class);

    private final static String DEFAULT_USERNAME = "admin";

    private final static String DEFAULT_PASSWORD = "admin";

    private final static String ALLOW = "allow";

    private final static String DENY = "deny";

    private final static String PRODUCT_KEY = "abcdef";

    private final Map<String, User> users = new HashMap<String, User>() {{
        put(DEFAULT_USERNAME, new User(DEFAULT_USERNAME, DEFAULT_PASSWORD, asList("administrator", "management")));
        put("springy", new User("springy", "springy", asList("administrator", "management")));
    }};

    @RequestMapping("user")
    public String user(@RequestParam("username") String username,
                       @RequestParam("password") String password) {
        LOGGER.info("Trying to authenticate user {} password {}", username, password);
        User user = users.get(username);
        //系统默认用户直接放过，用于服务端访问及测试
        if (user != null && user.getPassword().equals(password)) {
            LOGGER.info("认证通过");
            return "allow " + collectionToDelimitedString(user.getTags(), " ");
        } else {
            //设备（客户端）用户
            if (username.contains("@")) {
                String[] array = username.split("@");
                if (array.length < 2) {
                    return DENY;
                }
                String deviceName = array[0];
                String productId = array[1];
                //开始验证密码
                String myPassword = this.genPassword(deviceName, productId);
                if (myPassword.equals(password)) { //密码验证通过
                    LOGGER.info("用户{}认证通过", username);
                    //去数据库验证是否存在该产品，如果设备是先注册到平台才允许连接，那么还需要校验deviceName，具体代码省略
                    return this.checkProduct(deviceName, productId) ? ALLOW : DENY;
                } else {
                    LOGGER.warn("用户{}认证失败", username);
                    return DENY;
                }
            } else {
                return DENY;
            }
        }
    }

    @RequestMapping("vhost")
    public String vhost(VirtualHostCheck check) {
        LOGGER.info("Checking vhost access with {}", check);
        return "allow";
    }

    @RequestMapping("resource")
    public String resource(ResourceCheck check) {
        LOGGER.info("Checking resource access with {}", check);
        return "allow";
    }

    //设备允许订阅的主题
    private static final List<String> deviceReadAllowTopic = Arrays.asList("topic/%s/%s/upload/reply");
    //设备允许发布的主题
    private static final List<String> deviceWriteAllowTopic = Arrays.asList("topic/%s/%s/upload");

    @RequestMapping("topic")
    public String topic(TopicCheck check) {
        LOGGER.info("校验topic={} ", check.getRouting_key());
        String username = check.getUsername();
        if (DEFAULT_USERNAME.equals(username)) { //默认管理员账户直接放过
            return ALLOW;
        }
        String permission = check.getPermission();
        String[] array = username.split("@");
        String deviceName = array[0];
        String productId = array[1];
        String routingKey = check.getRouting_key();
        String topic = routingKey.replaceAll("\\.", "/");
        if ("read".equals(permission)) {
            for (String s : deviceReadAllowTopic) {
                String f = String.format(s, deviceName, productId);
                if (f.equals(topic)) { //匹配上了则放过
                    return ALLOW;
                }
            }
            LOGGER.warn("设备{}订阅主题{}不在允许的列表内", username, topic);
            return DENY;
        } else if ("write".equals(permission)) {
            for (String s : deviceWriteAllowTopic) {
                String f = String.format(s, deviceName, productId);
                if (f.equals(topic)) { //匹配上了则放过
                    return ALLOW;
                }
            }
            LOGGER.warn("设备{}发布主题{}不在允许的列表内", username, topic);
            return DENY;
        } else {
            return ALLOW;
        }
    }

    private String genPassword(String deviceName, String productId) {
        return Md5Utils.hash(deviceName + productId + PRODUCT_KEY);
    }

    private boolean checkProduct(String deviceName, String productId) {
        return true;
    }

    public static void main(String[] args) {
        String deviceName = "87654321";
        String productId = "123456";
        String productKey = PRODUCT_KEY;
        String password = Md5Utils.hash(deviceName + productId + productKey);
        System.out.println(password);
    }
}


